package eco2automotive.port;
import java.util.*;
import gnu.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;

import gnu.io.UnsupportedCommOperationException;
import eco2automotive.Log.LogInformation;
import eco2automotive.Log.Log; 
import eco2automotive.Log.TXRXInformation;
import eco2automotive.util.Fifo;
import eco2automotive.lang.EN;

/**  
  * Confinguration from "Connection" object. </br>
  *  Create two streams (read/write)</br>
  * Try to open the COM port
  * @version 1.0
  * @autor Fco. Javier Sánchez Esparza
  *
  */ 

public class ConnectionControl implements Runnable,SerialPortEventListener,Log{

InputStream in = null;
OutputStream out;

StringBuffer tramaEnviada;
SerialPort serial_PORT = null;
CommPortIdentifier idPuerto;
Connection conn;
Thread thread_Read;
boolean isActiveConnection=false;
LogInformation log;
TXRXInformation logTR;
String data;
Fifo fifo;
boolean FLAG_OF_DATA=false;

/**
  * Constructs a new object
 * @throws Exception
 */
public ConnectionControl() throws Exception{}
/**
 * Set the port configuration, create a new fifo structure
 * @param conn Connection object
 * @throws Exception 
 * @see eco2automotive.port.Connection
 * @see eco2automotive.util.Fifo
 */
public ConnectionControl( Connection conn) throws Exception {
  log=new LogInformation();
  logTR=new TXRXInformation();
  fifo = new Fifo();
  this.conn=conn;  
   idPuerto =CommPortIdentifier.getPortIdentifier(conn.getNombrePuerto());
   log.addLogInformation(String.valueOf("\n"+idPuerto));
}
/**
 * Connect to port
 */
public void connect(){
if(this.isActiveConnection==false){ 
    log.addLogInformation(EN.PORT_CONNECT_Ini);     
      if( idPuerto.getPortType() == CommPortIdentifier.PORT_SERIAL ) {
//    Vs.UNIX    if( idPuerto.getName().equals("/dev/term/a") ) {
        if( idPuerto.getName().equals(conn.getNombrePuerto()) ) {
          try {
            // Try to open 
            serial_PORT = ( SerialPort )idPuerto.open(EN.APP_NAME,
                    conn.getTimeOut());        
          } catch( PortInUseException e ) 
            {log.addLogInformation(EN.PORT_ERROR_PortInUseException);}
          try {            
              log.addLogInformation(EN.PORT_CONNECT_INI_CHANNEL_IN_OUT);
            in = serial_PORT.getInputStream();  
            out = serial_PORT.getOutputStream();
          } catch( IOException e ) {log.addLogInformation(EN.PORT_ERROR_IO);}

          try{
           /*Adding a event listener */
          serial_PORT.addEventListener(this);         }
          catch(TooManyListenersException e){}                            
          serial_PORT.notifyOnDataAvailable(true);
         
          try {             
            serial_PORT.setSerialPortParams( conn.getBaud(),conn.getDataBits(),
            conn.getStopBits(),conn.getParity() );
            serial_PORT.setFlowControlMode(conn.getFlowControlMode());
            serial_PORT.enableReceiveThreshold(1);
            serial_PORT.enableReceiveTimeout(conn.getTimeOut());       
            
          } catch( UnsupportedCommOperationException e ) {}          
          thread_Read=new Thread(this);
          thread_Read.start();
          thread_Read.setPriority(Thread.MIN_PRIORITY);
          this.isActiveConnection=true;         
          log.addLogInformation(EN.PORT_CONNECT_Port_info_Name
                  +this.conn.getNombrePuerto());
          log.addLogInformation(EN.PORT_CONNECT_INI_WAIT);
        }
      }
}else{    
        log.addLogInformation(EN.PORT_ERROR_PortInUseException);
     }

} 
/**
 * Transfer data 
 * @param data String to send
 */
public void TXData(String data)
{
 int bytetosend;
 if(this.isActiveConnection){
      data=data.concat("\r"); //end of instruction
      logTR.addTXInformation("\n"+data);                        
      try{           
          for(int i=0;i<data.length();i++){
              bytetosend=data.codePointAt(i);     
              out.write(bytetosend);        
          }
             out.write(13);
      }catch(Exception e){
      logTR.addTXInformation("Error: "+e);                        
      }
 }
 else{
 log.addLogInformation(EN.PORT_ERROR_Not_Connected);
 }
}
/**
 * Get TX information
 * @return
 */
public String getTXinfo(){return logTR.getTXInformation();}
/**
 * No data available
 */
public synchronized void downFlag(){this.FLAG_OF_DATA=false;}
/**
 * Get RX information
 * @return FLAG_OF_DATA util flag
 */ 
public synchronized String getRXinfo(){this.FLAG_OF_DATA=false;return logTR.getRXInformation();}
public String getLogInformation(){return log.getLogInformation();}
/**
 * Is active?
 * @return boolean
 */
public boolean getIsActiveConnection(){return this.isActiveConnection;}
/**
 * If the FLAG_OF_DATA == true then give me data
 * @return data 
 */
public synchronized String getData(){return this.data;}
/**
 * Create a new fifo structure
 */
public void clearFifo(){this.fifo=new Fifo();}
/**
 * The fifo active
 * @return fifo 
 */
public synchronized Fifo getFata(){return this.fifo;}
/**
 * Data available?
 * @return FLAG_OF_DATA boolean status
 */
public synchronized boolean DATA_AVAILABLE(){return this.FLAG_OF_DATA;}
/**
 * Disconnect from active port
 */
public void disconnect(){  
    if(this.isActiveConnection==true){
        thread_Read=null;
        try{
        log.clear();
        log.addLogInformation(EN.PORT_DISConnecting_inf);
        this.serial_PORT.close();
        this.isActiveConnection=false;
        log.addLogInformation(EN.PORT_DISConnecting_inf_END+this.idPuerto.getName());
        }
        catch(Exception e){ log.addLogInformation(e.toString());}   
    }
   
    
}
public void run(){        
    try{Thread.sleep(20000);}
    catch(InterruptedException e){
     log.addLogInformation(e.getMessage());
    }
}
/**
 * Serial Event listener
 * @param _ev
 */
public void serialEvent(SerialPortEvent _ev) {
      switch(_ev.getEventType()){
      case SerialPortEvent.BI:
      case SerialPortEvent.OE:
      case SerialPortEvent.FE:
      case SerialPortEvent.PE:
      case SerialPortEvent.CD:
      case SerialPortEvent.CTS:
      case SerialPortEvent.DSR:
      case SerialPortEvent.RI:
      case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
        break;
      case SerialPortEvent.DATA_AVAILABLE:{          
          int leidoByte=0;
          char toChar;           
          try{
            StringBuffer msgHEX=new StringBuffer();             
            while(in.available()>0 || leidoByte>-1)
                {                                        
                    leidoByte=in.read();
                    toChar=(char)leidoByte;

                            if (leidoByte==62){  // --- 62: '>' //                   
                               // this.logTR.addRXInformation("RX >"); //no hacemos nada
                                
                            }
                            else if(leidoByte!=-1){ //? --- END                       
                                msgHEX=msgHEX.append(toChar);                         
                            }                                                                                             
                  }
            
                 System.out.println("<< END MSG >> "+msgHEX.toString());                 
                 this.data=msgHEX.toString();                                 
                 this.fifo.add(new String(data));
                 this.logTR.addRXInformation(msgHEX.toString());              
                 this.FLAG_OF_DATA=true;               
              }                  
          catch(IOException e){}break;                    
        }  //END OF .... case SerialPortEvent.DATA_AVAILABLE:{
      }
    }

}